package one

import (
	"fmt"
	"gorm.io/gorm"
	"strings"
)

// 单表查询工具

// 核心查询函数
// SingleQuery 查询构建器
type SingleQuery struct {
	db           *gorm.DB
	table        interface{}    //查询表-必填
	selectFields []string       //展示字段-可选
	wheres       []whereClause  //条件-可选
	groups       []string       //分组-可选
	havings      []havingClause //分组条件-可选
	orders       []string       //排序-可选
	pageNum      int            //页码-可选
	pageSize     int            //条数-可选
}

type whereClause struct {
	query interface{}
	args  []interface{}
}

type havingClause struct {
	query interface{}
	args  []interface{}
}

func NewSingleQuery(db *gorm.DB, table interface{}) *SingleQuery {
	return &SingleQuery{
		db:    db,
		table: table,
	}
}

// ---------------------------------------设置参数--------------------------------------------------
// Select()
func (this *SingleQuery) Select(fields ...string) *SingleQuery {
	this.selectFields = fields
	return this
}

// Where()
func (this *SingleQuery) Where(param interface{}, args ...interface{}) *SingleQuery {
	this.wheres = append(this.wheres, whereClause{param, args})
	return this
}

// Group()
func (this *SingleQuery) GroupBy(fields ...string) *SingleQuery {
	this.groups = append(this.groups, fields...)
	return this
}

// Having()
func (this *SingleQuery) Having(param interface{}, args ...interface{}) *SingleQuery {
	this.havings = append(this.havings, havingClause{param, args})
	return this
}

// OrderBy()
func (this *SingleQuery) OrderBy(fields ...string) *SingleQuery {
	this.orders = append(this.orders, fields...)
	return this
}

// OrderBy 降序
func (this *SingleQuery) OrderByDesc(field string) *SingleQuery {
	return this.OrderBy(fmt.Sprintf("%s DESC", field))
}

// OrderBy 升序
func (this *SingleQuery) OrderByAsc(field string) *SingleQuery {
	return this.OrderBy(fmt.Sprintf("%s ASC", field))
}

// Page() 设置分页
func (this *SingleQuery) Page(pageNum, pageSize int) *SingleQuery {
	this.pageNum = pageNum
	this.pageSize = pageSize
	return this
}

// ---------------------------------------查询函数--------------------------------------------------
// First() 查询一条
func (this *SingleQuery) First() error {
	query := this.buildQuery()
	return query.First(this.table).Error
}

// Find() 查询列表
func (this *SingleQuery) Find() error {
	query := this.buildQuery()
	return query.Find(this.table).Error
}

// Count() 统计条数
func (this *SingleQuery) Count() (int64, error) {
	//query := this.buildQuery()
	//
	//// 计算总数
	//var total int64
	//err := query.Model(this.table).Count(&total).Error
	//return total, err

	// 改进的 Count 方法
	// 构建基础查询但不包含 SELECT 字段
	query := this.db.Model(this.table)
	// 应用 WHERE 条件
	for _, where := range this.wheres {
		query = query.Where(where.query, where.args...)
	}
	// 处理 GROUP BY 的情况
	if len(this.groups) > 0 {
		// 对于 GROUP BY 查询，使用子查询计数
		subQuery := query.Table("(?) as count_table",
			this.buildQuery().Select("1"))
		var total int64
		err := subQuery.Count(&total).Error
		return total, err
	}
	// 普通计数
	var total int64
	err := query.Count(&total).Error
	return total, err
}

// 构建查询
func (this *SingleQuery) buildQuery() *gorm.DB {
	//query := this.db

	//根据泛型返回需要这样
	query := this.db.Model(this.table)

	// 拼接显示字段
	if len(this.selectFields) > 0 {
		query = query.Select(strings.Join(this.selectFields, ","))
	}

	// 拼接条件
	if len(this.wheres) > 0 {
		for _, where := range this.wheres {
			query = query.Where(where.query, where.args...)
		}
	}

	// 拼接分组
	if len(this.groups) > 0 {
		query = query.Group(strings.Join(this.groups, ","))
	}

	// 拼接分组条件
	if len(this.havings) > 0 {
		for _, having := range this.havings {
			query = query.Having(having.query, having.args...)
		}
	}

	// 拼接排序
	if len(this.orders) > 0 {
		query = query.Order(strings.Join(this.orders, ","))
	}

	return query
}

// ---------------------------------------分页查询--------------------------------------------------
// 分页结果结构体
type PaginateResult struct {
	Page      int   `json:"page"`       // 当前页码
	PageSize  int   `json:"page_size"`  // 每页大小
	Total     int64 `json:"total"`      // 总记录数
	TotalPage int   `json:"total_page"` // 总页数
}

// 分页获取偏移量（辅助方法）
func (this *SingleQuery) GetOffset() int {
	if this.pageNum <= 0 {
		return 0
	}
	return (this.pageNum - 1) * this.pageSize
}

// 分页获取限制数（辅助方法）
func (this *SingleQuery) GetLimit() int {
	return this.pageSize
}

// Paginate() 分页查询
func (this *SingleQuery) Paginate() (*PaginateResult, error) {
	// 计算总数
	total, err := this.Count()
	if err != nil {
		return nil, err
	}

	// 构建基础查询（不包含分页）
	baseQuery := this.buildQuery()

	// 计算总页数
	totalPage := 0
	if total > 0 && this.pageSize > 0 {
		totalPage = int((total + int64(this.pageSize) - 1) / int64(this.pageSize))
	}

	// 应用分页查询数据
	query := baseQuery
	if this.pageNum > 0 && this.pageSize > 0 {
		offset := (this.pageNum - 1) * this.pageSize
		query = query.Offset(offset).Limit(this.pageSize)
	}

	// 执行查询
	if err := query.Find(this.table).Error; err != nil {
		return nil, err
	}

	// 返回分页结果
	return &PaginateResult{
			Page:      this.pageNum,
			PageSize:  this.pageSize,
			Total:     total,
			TotalPage: totalPage,
		},
		nil
}

// ---------------------------------------函数式泛型（保持函数形式）--------------------------------------------------
//灵活使用：可以在同一个查询表的基础上，返回不同的结构体类型
//FirstTo[T]()：查询单条到指定类型
//FindTo[T]()：查询列表到指定类型
//PaginateTo[T]()：分页查询到指定类型

// FirstTo() 查询一条返回指定T泛型
func FirstTo[T any](this *SingleQuery) (*T, error) {
	query := this.buildQuery()
	var result T
	err := query.First(&result).Error
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// FindTo() 查询列表返回指定T泛型
func FindTo[T any](this *SingleQuery) ([]T, error) {
	query := this.buildQuery()
	var results []T
	err := query.Find(&results).Error
	if err != nil {
		return nil, err
	}
	return results, nil
}

// PaginateTo() 分页查询返回指定T泛型
func PaginateTo[T any](this *SingleQuery) ([]T, *PaginateResult, error) {
	// 计算总数
	total, err := this.Count()
	if err != nil {
		return nil, nil, err
	}

	// 构建基础查询（不包含分页）
	baseQuery := this.buildQuery()

	// 计算总页数
	totalPage := 0
	if total > 0 && this.pageSize > 0 {
		totalPage = int((total + int64(this.pageSize) - 1) / int64(this.pageSize))
	}

	// 应用分页查询数据
	query := baseQuery
	if this.pageNum > 0 && this.pageSize > 0 {
		offset := (this.pageNum - 1) * this.pageSize
		query = query.Offset(offset).Limit(this.pageSize)
	}

	// 执行查询到指定类型
	var results []T
	if err := query.Find(&results).Error; err != nil {
		return nil, nil, err
	}

	// 返回分页结果
	paginateResult := &PaginateResult{
		Page:      this.pageNum,
		PageSize:  this.pageSize,
		Total:     total,
		TotalPage: totalPage,
	}

	return results, paginateResult, nil
}
